/**
 * 
 */
package eval;

import java.io.IOException;
import java.util.Vector;

import main.Driver;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Mapper.Context;

import dataStructures.CodeBook;
import dataStructures.ErrorElementWritable;
import dataStructures.FilesAndPaths;
import dataStructures.ProfileWritable;

/**
 * @author zvikadori
 *
 */
public class EvalMapper extends  Mapper<NullWritable, ProfileWritable, IntWritable, ErrorElementWritable> {
	private final static IntWritable one = new IntWritable(1);
	private int currentIter = 0;
	private Configuration conf;
	private int userArr[];
	private int itemArr[];
	private double codeBookMatrix[][];
	
	@Override
	protected void setup(Context context)
			throws IOException, InterruptedException {
		// TODO Auto-generated method stub
		super.setup(context);
		conf = context.getConfiguration();
		currentIter = conf.getInt("iteration", 0);
		Vector<CodeBook> usersData = 
				Driver.getDataFromIteration(conf, currentIter, FilesAndPaths.CODEBOOK_USER_DIR_NAME);
		Vector<CodeBook> itemData = 
				Driver.getDataFromIteration(conf, currentIter, FilesAndPaths.CODEBOOK_ITEM_DIR_NAME);
		
		userArr = Driver.convertCodeBookVectorToArr(usersData, Driver.Q+1);
		itemArr = Driver.convertCodeBookVectorToArr(itemData, Driver.P+1);
		codeBookMatrix = 
				Driver.convertItemCodeBookVectorToMatrixValues(itemData, Driver.K, Driver.L);
	}
	
	@Override
	public void map(NullWritable key, ProfileWritable value,
			Context context) throws IOException, InterruptedException {
		int ratedSamples[] = value.getRated();
		int sampleSize = ratedSamples.length;
		int ratingSamples[] = value.getRating();
		int rater = value.getRater();
		long squareError = 0;
		for (int i=0; i<sampleSize; i++){
			int rated = ratedSamples[i];
			int rating = ratingSamples[i];
			//Take the user predicted score from B - realScore(from value) and take its square
			squareError+= Math.pow(getRating(rater,rated) - rating, 2);
			
			
		}
		ErrorElementWritable w = new ErrorElementWritable();
		w.setProfileSampleSize(sampleSize);
		w.setTotalSquareError(squareError);
		context.write(one, w);
		
	}
	
	private double getRating(int userID, int itemID){
		double ans = this.codeBookMatrix[this.userArr[userID]][this.itemArr[itemID]];
		if (ans < 1)
			return 0; //something bad happened!!
		return ans;
		
	}
	
	

}
